<?php abstract class Filter implements iReconfigurable {
	protected static $Root    = NULL;
	protected static $Plugins = array ();
	protected static $Seen    = array ();
	protected static function PushPlugin ($Plugin) {self::$Plugins [$Plugin] = TRUE;}
	public static function Reconfigure (array $Config) {
		$Root = new FilterNodeRoot ();
		$Prefixes = array ('cur' => -1, -1 => array ('self' => $Root, 'parent' => $Root));
		if (! array_key_exists ('config', $Config)) {
			Out::W (Msg::ConfigMiss, 'config');
			return (FALSE);
		} else Out::I (Msg::ConfigGot, 'config', $Config = $Config ['config']);
		if (! is_readable ($Config)) {
			Out::W (Msg::NotReadable, $Config);
			return (FALSE);
		}
		foreach (file ($Config) as $LineNo => $Line) {
			$LineNo += 1;
			$Preflen = strspn ($Line, " \t");
			$Line = trim ($Line);
			if ((strlen ($Line) < 1) or ('#' === substr ($Line, 0, 1))) continue;
			if ($Preflen > $Prefixes ['cur']) { // indent
				$Parent = $Prefixes [$Prefixes ['cur']]['self'];
			} elseif ($Preflen < $Prefixes ['cur']) { // outdent
				if (! array_key_exists ($Preflen, $Prefixes)) {
					Out::W (Msg::FilterInvalidPrfx, $LineNo);
					continue;
				}
				$Parent = $Prefixes [$Preflen]['parent'];
			} else { // preflen is the same
				$Parent = $Prefixes [$Prefixes ['cur']]['parent'];
			}
			$Node = $Parent->AddString ($LineNo, $Line);
			$Prefixes [$Preflen] = array ('self' => $Node, 'parent' => $Parent);
			$Prefixes ['cur'] = $Preflen;
		}
		self::$Root = $Root;
		Out::D (Msg::ConfigDump, $Config, self::$Root->Render ());
		return (TRUE);
	}
	public static function Examine ($Line) {
		$Line ['message'] = trim ($Line ['message']);
		array_push (self::$Seen, $Line ['id']);
		Out::D (Msg::FilterExamineLine, $Line ['message']);
		$Chain = self::$Root->Examine ($Line);
		foreach ($Chain as $Action) {
			Out::D (Msg::FilterAction, $Action);
			call_user_func (array ($Action, 'Action'), $Line);
			self::PushPlugin ($Action);
		}
	}
	public static function Commit () {
		foreach (array_keys (self::$Plugins) as $Plugin) call_user_func (array ($Plugin, __FUNCTION__));
		self::$Plugins = array ();
		if (count (self::$Seen)) {
			Out::I (Msg::MakingSeen, implode (', ', self::$Seen));
			DB::See (self::$Seen);
			self::$Seen = array ();
		}
	}
} ?>